package net.osmand.plus.activities;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import net.osmand.Algoritms;
import net.osmand.FavouritePoint;
import net.osmand.LogUtil;
import net.osmand.OsmAndFormatter;
import net.osmand.Version;
import net.osmand.data.AmenityType;
import net.osmand.data.MapTileDownloader;
import net.osmand.data.MapTileDownloader.DownloadRequest;
import net.osmand.data.MapTileDownloader.IMapDownloaderCallback;
import net.osmand.map.IMapLocationListener;
import net.osmand.map.ITileSource;
import net.osmand.osm.LatLon;
import net.osmand.plus.BusyIndicator;
import net.osmand.plus.FavouritesDbHelper;
import net.osmand.plus.NavigationService;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.OsmandSettings.ApplicationMode;
import net.osmand.plus.PoiFilter;
import net.osmand.plus.PoiFiltersHelper;
import net.osmand.plus.ResourceManager;
import net.osmand.plus.SQLiteTileSource;
import net.osmand.plus.activities.search.SearchActivity;
import net.osmand.plus.activities.search.SearchPoiFilterActivity;
import net.osmand.plus.render.MapRenderRepositories;
import net.osmand.plus.views.AnimateDraggingMapThread;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.RouteInfoLayer;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.ZoomControls;

import com.dualsportmaps.android.DsmConnectionFactory;
import com.dualsportmaps.android.DsmMapDownload;
import com.dualsportmaps.android.DsmRemoteControlManager;
import com.dualsportmaps.android.DsmResourceManager;
import com.dualsportmaps.android.DsmResourceManager.DsmResourceManagerException;
import com.dualsportmaps.android.DsmResourceManager.GPXProcessRequest;
import com.dualsportmaps.android.GPXUtilities.GPXFileResult;
import com.dualsportmaps.android.IDsmRemoteControlListener;
import com.dualsportmaps.android.R;
import com.dualsportmaps.android.Utils;
import com.dualsportmaps.android.activities.DsmMapTileOverlayDownloadActivity;
import com.dualsportmaps.android.views.DsmActiveLogLayer;
import com.dualsportmaps.android.views.DsmAppUserLocationLayer;
import com.dualsportmaps.android.views.DsmContextMenuLayer;
import com.dualsportmaps.android.views.DsmFavoritesLayer;
import com.dualsportmaps.android.views.DsmMapInfoLayer;
import com.dualsportmaps.android.views.DsmMapLayer;
import com.dualsportmaps.android.views.DsmMapTileOverlayLayer;
import com.dualsportmaps.android.views.DsmPOIMapLayer;
import com.dualsportmaps.android.views.DsmPointLocationLayer;
import com.dualsportmaps.android.views.DsmPointNavigationLayer;
import com.dualsportmaps.android.views.DsmRendererLayer;
import com.dualsportmaps.android.views.DsmRouteLayer;
import com.dualsportmaps.android.views.DsmSpeedometerLayer;
import com.dualsportmaps.android.views.DsmTrafficLayer;
import com.dualsportmaps.android.views.DsmUtmLayer;
import com.dualsportmaps.android.views.DsmWeatherLayer;

public class MapActivity extends Activity implements IMapLocationListener, SensorEventListener, IDsmRemoteControlListener {

	private static final String GPS_STATUS_ACTIVITY = "com.eclipsim.gpsstatus2.GPSStatus"; //$NON-NLS-1$
	private static final String GPS_STATUS_COMPONENT = "com.eclipsim.gpsstatus2"; //$NON-NLS-1$
	
	// stupid error but anyway hero 2.1 : always lost gps signal (temporarily unavailable) for timeout = 2000
	private static final int GPS_TIMEOUT_REQUEST = 1000;
	private static final int GPS_DIST_REQUEST = 5;
	// use only gps (not network) for 12 seconds 
	private static final int USE_ONLY_GPS_INTERVAL = 12000; 
	
	private boolean providerSupportsBearing = false;
	@SuppressWarnings("unused")
	private boolean providerSupportsSpeed = false;
	private String currentLocationProvider = null;
	private long lastTimeAutoZooming = 0;
	private long lastTimeGPXLocationFixed = 0;
	
    /** Called when the activity is first created. */
	private OsmandMapTileView mapView;
	private MapActivityActions mapActions = new MapActivityActions(this);
	
	private ImageButton backToLocation;
	private ImageButton backToMenu;
	
	// the order of layer should be preserved ! when you are inserting new layer
	private DsmRendererLayer rendererLayer;
	private DsmMapTileOverlayLayer mapOverlayLayer;
	private DsmWeatherLayer dsmWeatherLayer;
	private DsmMapLayer dsmMapLayer;
	private DsmActiveLogLayer dsmActiveLogLayer;
	private DsmRouteLayer routeLayer;
	private DsmUtmLayer dsmUtmLayer;
	private DsmTrafficLayer trafficLayer;
	private DsmPOIMapLayer poiMapLayer;
	private DsmFavoritesLayer favoritesLayer;
	private DsmPointLocationLayer locationLayer;
	private DsmPointNavigationLayer navigationLayer;
	private DsmMapInfoLayer mapInfoLayer;
	private DsmContextMenuLayer contextMenuLayer;
	private RouteInfoLayer routeInfoLayer;
	private DsmAppUserLocationLayer dsmAppUserLocationLayer; 
	private DsmSpeedometerLayer dsmSpeedometerLayer;
	
	private SeekBar overlayAlpha;
	
	private SavingTrackHelper savingTrackHelper;
	private RoutingHelper routingHelper;
//	private DsmResourceManager dsmResourceManager;
	
	private WakeLock wakeLock;
	private boolean sensorRegistered = false;

	private NotificationManager mNotificationManager;
	private Handler mapPositionHandler = null;
	private int APP_NOTIFICATION_ID;
	private int currentScreenOrientation;
	private int currentMapRotation;
	private boolean currentShowingAngle;
	
	private Dialog progressDlg = null;
	private SharedPreferences settings;
	private AudioManager audioManager;
	private boolean isMapLinkedToLocation(){
		return OsmandSettings.isMapSyncToGpsLocation(settings);
	}
	
	private Notification getNotification(){
		Intent notificationIndent = new Intent(this, MapActivity.class);
		notificationIndent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
		Notification notification = new Notification(R.drawable.icon, "", //$NON-NLS-1$
				System.currentTimeMillis());
		notification.setLatestEventInfo(this, Version.APP_NAME,
				getString(R.string.go_back_to_osmand), PendingIntent.getActivity(
						this, 0, notificationIndent,
						PendingIntent.FLAG_UPDATE_CURRENT));
		return notification;
	}
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		settings = OsmandSettings.getPrefs(this);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
		DsmResourceManager.getDsmResourceManager((OsmandApplication)getApplication()).setMapActivity(this);
		// for voice navigation
		setVolumeControlStream(AudioManager.STREAM_MUSIC); 
		// Full screen is not used here
//	     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.main);
		ProgressDialog dlg = ((OsmandApplication)getApplication()).checkApplicationIsBeingInitialized(this);
		if(dlg != null){
			// Do some action on close
			dlg.setOnDismissListener(new DialogInterface.OnDismissListener(){
				@Override
				public void onDismiss(DialogInterface dialog) {
					OsmandApplication app = ((OsmandApplication)getApplication());
					if(OsmandSettings.isUsingMapVectorData(settings) && app.getResourceManager().getRenderer().isEmpty()){
						Toast.makeText(MapActivity.this, getString(R.string.no_vector_map_loaded), Toast.LENGTH_LONG).show();
					}
				}
			});
		}
		parseLaunchIntentLocation();
		
		mapView = (OsmandMapTileView) findViewById(R.id.MapView);
		mapView.setTrackBallDelegate(new OsmandMapTileView.OnTrackBallListener(){
			@Override
			public boolean onTrackBallEvent(MotionEvent e) {
				showAndHideMapPosition();
				return MapActivity.this.onTrackballEvent(e);
			}

		});
		MapTileDownloader.getInstance().addDownloaderCallback(new IMapDownloaderCallback(){
			@Override
			public void tileDownloaded(DownloadRequest request) {
				if(request != null && !request.error && request.fileToSave != null){
					ResourceManager mgr = ((OsmandApplication)getApplication()).getResourceManager();
					mgr.tileDownloaded(request);
				}
				mapView.tileDownloaded(request);
				
			}
		});
		
		mapView.setMapLocationListener(this);
		routingHelper = ((OsmandApplication) getApplication()).getRoutingHelper();
		
		dsmSpeedometerLayer = (DsmSpeedometerLayer) findViewById(R.id.DsmSpeedometerLayer);
		
		// 0.5 layer
		rendererLayer = new DsmRendererLayer();
		mapView.addLayer(rendererLayer, 0.5f);

		mapOverlayLayer = new DsmMapTileOverlayLayer();
		mapView.addLayer(mapOverlayLayer, 0.51f);
		
		overlayAlpha = (SeekBar) findViewById(R.id.OverlayAlpha);
		overlayAlpha.setMax(255);
		overlayAlpha.setProgress(OsmandSettings.getMapTileOverlayAlpha(settings));
		mapOverlayLayer.setAlpha(overlayAlpha.getProgress());
		overlayAlpha.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			@Override
			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				mapOverlayLayer.setAlpha(progress);
				OsmandSettings.setMapTileOverlayAlpha(MapActivity.this,progress);
			}

			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {

			}

			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				
			}});
		
		dsmWeatherLayer = new DsmWeatherLayer();
//		mapView.addLayer(dsmWeatherLayer, 0.53f);
		
		dsmMapLayer = new DsmMapLayer();
		mapView.addLayer(dsmMapLayer, 0.55f);
		
		dsmActiveLogLayer = new DsmActiveLogLayer();
		mapView.addLayer(dsmActiveLogLayer, 0.75f);
		
		dsmAppUserLocationLayer = new DsmAppUserLocationLayer();
		mapView.addLayer(dsmAppUserLocationLayer, 0.80f);
		
		dsmUtmLayer = new DsmUtmLayer();
		mapView.addLayer(dsmUtmLayer, 0.85f);
		
		// 1. route layer
		routeLayer = new DsmRouteLayer(routingHelper);
		mapView.addLayer(routeLayer, 1);
		
		// 1.5. traffic layer
		trafficLayer = new DsmTrafficLayer();
		
		// 3. poi layer
		poiMapLayer = new DsmPOIMapLayer();
		// 4. favorites layer
		favoritesLayer = new DsmFavoritesLayer();
		// 6. point navigation layer
		navigationLayer = new DsmPointNavigationLayer();
		mapView.addLayer(navigationLayer, 6);
		// 7. point location layer 
		locationLayer = new DsmPointLocationLayer();
		mapView.addLayer(locationLayer, 7);
		// 8. map info layer
		mapInfoLayer = new DsmMapInfoLayer(routeLayer);
		mapView.addLayer(mapInfoLayer, 8);
		// 9. context menu layer 
		contextMenuLayer = new DsmContextMenuLayer();
		mapView.addLayer(contextMenuLayer, 9);
		// 10. route info layer
		routeInfoLayer = new RouteInfoLayer(routingHelper, (LinearLayout) findViewById(R.id.RouteLayout));
		mapView.addLayer(routeInfoLayer, 10);
		
		
		savingTrackHelper = new SavingTrackHelper(this);
		
		LatLon pointToNavigate = OsmandSettings.getPointToNavigate(settings);
		
		// This situtation could be when navigation suddenly crashed and after restarting
		// it tries to continue the last route
		if(!Algoritms.objectEquals(routingHelper.getFinalLocation(), pointToNavigate)){
			if(routingHelper.isFollowingMode()) {
				routingHelper.setFollowingMode(false);
				routingHelper.setFinalAndCurrentLocation(pointToNavigate, null);
			}
		}
		if(OsmandSettings.isFollowingByRoute(settings)){
			if(pointToNavigate == null){
				OsmandSettings.setFollowingByRoute(this, false);
			} else if(!routingHelper.isRouteCalculated()){
				Builder builder = new AlertDialog.Builder(this);
				builder.setMessage(R.string.continue_follow_previous_route);
				builder.setPositiveButton(R.string.default_buttons_yes, new DialogInterface.OnClickListener(){
					@Override
					public void onClick(DialogInterface dialog, int which) {
						routingHelper.setFollowingMode(true);
						((OsmandApplication)getApplication()).showDialogInitializingCommandPlayer(MapActivity.this);
					}
				});
				builder.setNegativeButton(R.string.default_buttons_no, new DialogInterface.OnClickListener(){
					@Override
					public void onClick(DialogInterface dialog, int which) {
						OsmandSettings.setFollowingByRoute(MapActivity.this, false);
						routingHelper.setFinalLocation(null);
						mapView.refreshMap();
					}
				});
				builder.show();
			}
		}
		
		navigationLayer.setPointToNavigate(pointToNavigate);
		
		SharedPreferences prefs = getSharedPreferences(OsmandSettings.SHARED_PREFERENCES_NAME, MODE_WORLD_READABLE);
		if(prefs == null || !prefs.contains(OsmandSettings.LAST_KNOWN_MAP_LAT)){
			LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
			Location location = null;
			try {
				location = service.getLastKnownLocation(LocationManager.GPS_PROVIDER);
			}
			catch(IllegalArgumentException e) {
				Log.d(LogUtil.TAG, "GPS location provider not available"); //$NON-NLS-1$
			}

			if(location == null){
				try {
					location = service.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
				} catch(IllegalArgumentException e) {
					Log.d(LogUtil.TAG, "Network location provider not available"); //$NON-NLS-1$
				}
			}
			if(location != null){
				mapView.setLatLon(location.getLatitude(), location.getLongitude());
				mapView.setZoom(14);
			}
		}
		
		
		final ImageButton mapMenuButton = (ImageButton)findViewById(R.id.MapMenuButton);
		mapMenuButton.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				openOptionsMenu();
			}
			
		});
		
		final ZoomControls zoomControls = (ZoomControls) findViewById(R.id.ZoomControls);
		updateZoomControls(zoomControls, mapView.getZoom());
		zoomControls.setOnZoomInClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				zoomIn();
			}
		});
		zoomControls.setOnZoomOutClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				zoomOut();
			}
		});
		backToLocation = (ImageButton)findViewById(R.id.BackToLocation);
		backToLocation.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				backToLocationImpl();
			}
			
		});
		
		
		
		backToMenu = (ImageButton)findViewById(R.id.BackToMenu);
		ApplicationMode mode = OsmandSettings.getApplicationMode(settings);
		if(mode == ApplicationMode.CAR) {
			backToMenu.setBackgroundResource(R.drawable.mode_car);
		} else if (mode == ApplicationMode.GAUGE) {
			backToMenu.setBackgroundResource(R.drawable.mode_gauge);
		} else if (mode == ApplicationMode.PEDESTRIAN) {
			backToMenu.setBackgroundResource(R.drawable.mode_pedestrian);
		} else if (mode == ApplicationMode.BICYCLE) {
			backToMenu.setBackgroundResource(R.drawable.mode_bicycle);
		} else {
			backToMenu.setBackgroundResource(R.drawable.mode_default);			
		}
		switchApplicationMode(mode);
		backToMenu.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				switchApplicationMode(null);
			}
		});
		DsmResourceManager.getDsmMapDownloadServiceManager();
		if(!parseLaunchIntentFile())
			showAllSelectedMaps();
		if(OsmandSettings.isInternetConnectionAvailable(DsmResourceManager.getApplicationContext()))
			DsmConnectionFactory.addDsmAppUseHistory();
	}
    private void zoomIn() {
    	final ZoomControls zoomControls = (ZoomControls) findViewById(R.id.ZoomControls);
    	updateZoomControls(zoomControls, mapView.getZoom() + 1);
		mapView.getAnimatedDraggingThread().stopAnimatingSync();
		mapView.getAnimatedDraggingThread().startZooming(mapView.getZoom(), mapView.getZoom() + 1);
		showAndHideMapPosition();
		// user can preview map manually switch off auto zoom while user don't press back to location
		if(OsmandSettings.isAutoZoomEnabled(settings)){
			locationChanged(mapView.getLatitude(), mapView.getLongitude(), null);
		}
    }
    private void zoomOut() {
    	final ZoomControls zoomControls = (ZoomControls) findViewById(R.id.ZoomControls);
    	updateZoomControls(zoomControls, mapView.getZoom() - 1);
		mapView.getAnimatedDraggingThread().stopAnimatingSync();
		mapView.getAnimatedDraggingThread().startZooming(mapView.getZoom(), mapView.getZoom() - 1);
		showAndHideMapPosition();
		// user can preview map manually switch off auto zoom while user don't press back to location
		if(OsmandSettings.isAutoZoomEnabled(settings)){
			locationChanged(mapView.getLatitude(), mapView.getLongitude(), null);
		}
    }
    private void switchApplicationMode(ApplicationMode forceMode) {
//    	System.out.println("switch mode start");
		// change global settings
    	ApplicationMode next = forceMode;
		ApplicationMode old = OsmandSettings.getApplicationMode(settings);
		if(forceMode == null) {
			if(old == ApplicationMode.GAUGE) {
				next = ApplicationMode.CAR;
				backToMenu.setBackgroundResource(R.drawable.mode_car);
			} else if(old == ApplicationMode.DEFAULT) {
				next = ApplicationMode.GAUGE;
				backToMenu.setBackgroundResource(R.drawable.mode_gauge);
			} else { //if(old == ApplicationMode.CAR)
				next = ApplicationMode.DEFAULT;
				backToMenu.setBackgroundResource(R.drawable.mode_default);
			}
		}
		if(next == ApplicationMode.GAUGE) {
			Editor edit = getSharedPreferences(OsmandSettings.SHARED_PREFERENCES_NAME, MODE_WORLD_WRITEABLE).edit();
			edit.putString(OsmandSettings.APPLICATION_MODE, next.name());
			edit.commit();
			dsmSpeedometerLayer.setVisibility(View.VISIBLE);
		} else {
			dsmSpeedometerLayer.setVisibility(View.GONE);
		}
		if (old != next || forceMode != null) {
			Editor edit = getSharedPreferences(OsmandSettings.SHARED_PREFERENCES_NAME, MODE_WORLD_WRITEABLE).edit();
			edit.putString(OsmandSettings.APPLICATION_MODE, next.name());
			SettingsActivity.setAppMode(next, edit, (OsmandApplication) getApplication(), old);
			edit.commit();
			updateApplicationModeSettings();	
			mapView.refreshMap();
		}
//		System.out.println("switch mode finish");
    }
    private void updateZoomControls(ZoomControls zoomControls, int zoom){
    	zoomControls.setIsZoomInEnabled(zoom < mapView.getMaximumShownMapZoom());
		zoomControls.setIsZoomOutEnabled(zoom > mapView.getMinimumShownMapZoom());
    }
 
    @Override
    public void onLowMemory() {
    	Toast.makeText(this, "Please turn off unneeded maps because you are running low on memory.", Toast.LENGTH_LONG);
    }
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
    	if (keyCode == KeyEvent.KEYCODE_SEARCH && event.getRepeatCount() == 1) {
			Intent newIntent = new Intent(MapActivity.this, SearchActivity.class);
			startActivity(newIntent);
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
    @Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_SEARCH && event.getRepeatCount() == 0) {
			if(Math.abs(event.getDownTime()-event.getEventTime()) < 200) {
				dsmMapSearch();
				return true;
			}
	    }
		if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
			contextMenuPoint(mapView.getLatitude(), mapView.getLongitude());
	    	return true;
		}
		return super.onKeyUp(keyCode, event);
	}
    private void dsmMapSearch() {
    	if(!OsmandSettings.isShowingDualsportmapsOverMap(settings)) {
			OsmandSettings.setShowDualsportmapsOverMap(MapActivity.this, true);
			updateLayers();
		}
		try {
			dsmMapLayer.searchDsmMapView();
		} catch (Exception e) {
			Toast.makeText(this, "Search Failed", Toast.LENGTH_LONG).show();
			e.printStackTrace();
		}
    }
	@Override
    public boolean onTrackballEvent(MotionEvent event) {
    	if(event.getAction() == MotionEvent.ACTION_MOVE && OsmandSettings.isUsingTrackBall(settings)){
    		float x = event.getX();
    		float y = event.getY();
    		LatLon l = mapView.getLatLonFromScreenPoint(mapView.getCenterPointX() + x * 15, mapView.getCenterPointY() + y * 15);
    		setMapLocation(l.getLatitude(), l.getLongitude());
    		return true;
    	} 
    	return super.onTrackballEvent(event);
    }
    
    @Override
    protected void onStart() {
    	super.onStart();
    	Intent i = getIntent();
    	boolean setupremote = i.getBooleanExtra("remotecontrol", false);
    	if(setupremote)
    		DsmResourceManager.setupRemote();
    }
    
    protected void setProgressDlg(Dialog progressDlg) {
		this.progressDlg = progressDlg;
	}
    
    protected Dialog getProgressDlg() {
		return progressDlg;
	}
    
    @Override
    protected void onStop() {
    	// TODO keep this check?
    	if(routingHelper.isFollowingMode()){
    		mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    		mNotificationManager.notify(APP_NOTIFICATION_ID, getNotification());
    	}
		if(progressDlg != null){
			progressDlg.dismiss();
			progressDlg = null;
		}
    	super.onStop();
    }
    
    @Override
    protected void onDestroy() {
    	super.onDestroy();
    	savingTrackHelper.close();
    	if(mNotificationManager != null){
    		mNotificationManager.cancel(APP_NOTIFICATION_ID);
    	}
    	mapActions = null;
    	MapTileDownloader.getInstance().removeDownloaderCallback(mapView);
    	DsmMapDownload.removeListener(dsmMapLayer);
    	DsmResourceManager.getDsmResourceManager((OsmandApplication)getApplication()).setMapActivity(null);
    	DsmResourceManager.getDsmMapDownloadServiceManager().stopService();
    }
    
    
    
    private void registerUnregisterSensor(Location location){
    	boolean show = (currentShowingAngle && location != null) || currentMapRotation == OsmandSettings.ROTATE_MAP_COMPASS;
    	// show point view only if gps enabled
		if (sensorRegistered && !show) {
			Log.d(LogUtil.TAG, "Disable sensor"); //$NON-NLS-1$
			((SensorManager) getSystemService(SENSOR_SERVICE)).unregisterListener(this);
			sensorRegistered = false;
			locationLayer.setHeading(null);
		} else if (!sensorRegistered && show) {
			Log.d(LogUtil.TAG, "Enable sensor"); //$NON-NLS-1$
			SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
			Sensor s = sensorMgr.getDefaultSensor(Sensor.TYPE_ORIENTATION);
			if (s != null) {
				sensorMgr.registerListener(this, s, SensorManager.SENSOR_DELAY_UI);
			}
			sensorRegistered = true;
		}
    }
    
    protected void backToLocationImpl() {
		backToLocation.setVisibility(View.INVISIBLE);
		if(!isMapLinkedToLocation()){
			OsmandSettings.setSyncMapToGpsLocation(MapActivity.this, true);
			if(locationLayer.getLastKnownLocation() != null) {
				Location lastKnownLocation = locationLayer.getLastKnownLocation();
				AnimateDraggingMapThread thread = mapView.getAnimatedDraggingThread();
				int fZoom = mapView.getZoom() < 15 ? 15 : mapView.getZoom();
				thread.startMoving(mapView.getLatitude(), mapView.getLongitude(), 
						lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude(), mapView.getZoom(), fZoom, 
						mapView.getSourceTileSize(), mapView.getRotate(), false);
			}
		}
		if(locationLayer.getLastKnownLocation() == null){
			Toast.makeText(this, R.string.unknown_location, Toast.LENGTH_LONG).show();
		}
	}
    
    private void updateSpeedBearing(Location location) {
		// For network/gps it's bad way (not accurate). It's widely used for testing purposes
    	// possibly keep using only for emulator case
//		if (!providerSupportsSpeed
    	if (isRunningOnEmulator()
    			&& locationLayer.getLastKnownLocation() != null && location != null) {
			if (locationLayer.getLastKnownLocation().distanceTo(location) > 3) {
				float d = location.distanceTo(locationLayer.getLastKnownLocation());
				long time = location.getTime() - locationLayer.getLastKnownLocation().getTime();
				float speed;
				if (time == 0) {
					speed = 0;
				} else {
					speed = ((float) d * 1000) / time ;
				}
				// incorrect in case of airplane
				if (speed > 100) {
					speed = 100;
				}
				location.setSpeed(speed);
			}
		}
    	if(!providerSupportsBearing && locationLayer.getLastKnownLocation() != null && location != null){
    		if(locationLayer.getLastKnownLocation().distanceTo(location) > 10){
    			location.setBearing(locationLayer.getLastKnownLocation().bearingTo(location));
    		}
    	}
	}
    
 
    public void setLocation(Location location){
    	if(Log.isLoggable(LogUtil.TAG, Log.DEBUG)){
    		Log.d(LogUtil.TAG, "Location changed " + location.getProvider()); //$NON-NLS-1$
    	}
    	if(location != null && OsmandSettings.isSavingTrackToGpx(this)) {
    		if(location.getProvider() != null)
    			if(location.getProvider().equals(LocationManager.GPS_PROVIDER))
    				savingTrackHelper.insertData(location.getLatitude(), location.getLongitude(), 
    						location.getAltitude(), location.getSpeed(), location.getTime(), settings);
		}
    	
    	if(location != null) {
        	if(System.currentTimeMillis() - NavigationService.lastTrack > NavigationService.TRACKING_INTERVAL && OsmandSettings.getServiceTrackingEnabled(settings) && OsmandSettings.isInternetConnectionAvailable(DsmResourceManager.getApplicationContext())) {
    			NavigationService.lastTrack = System.currentTimeMillis();
        		DsmConnectionFactory.addDsmAppUserLocation(location.getLatitude(), location.getLongitude());
    		}
        	if(location.getProvider().equals(LocationManager.GPS_PROVIDER) && dsmSpeedometerLayer.getVisibility() == View.VISIBLE) {
        		dsmSpeedometerLayer.setData();
        		if(location.hasSpeed())
        			dsmSpeedometerLayer.setSpeed(location.getSpeed());
        		else
        			dsmSpeedometerLayer.setSpeed(0);
        		if(location.hasAltitude())
        			dsmSpeedometerLayer.setElevation(location.getAltitude());
        		if(location.hasBearing()) {
        			dsmSpeedometerLayer.setCompass(location.getBearing());
        		} else {
        			dsmSpeedometerLayer.setCompass(-1); //go back to compass
        		}
        	}
    	}    	
    	registerUnregisterSensor(location);
    	updateSpeedBearing(location);
    	
    	try {
			if (location != null) { //AUTO VOLUME STUFF
				int SPEED_TO_CHANGE = 13; //meters per second about 30 MPH
				if(OsmandSettings.isUsingAutoVolume(settings) && audioManager.isMusicActive()) {
					boolean changeVolume = false;
			    	if(location.hasSpeed() && locationLayer.getLastKnownLocation() != null) {
						if(locationLayer.getLastKnownLocation().hasSpeed()) {
							if((location.getSpeed() > SPEED_TO_CHANGE &&  locationLayer.getLastKnownLocation().getSpeed() < SPEED_TO_CHANGE) || 
							   (location.getSpeed() < SPEED_TO_CHANGE &&  locationLayer.getLastKnownLocation().getSpeed() > SPEED_TO_CHANGE)
							) {
								changeVolume = true;
							}
						}
			    	}
			    	if(changeVolume) {
			    		int toVolume = 0;
			    		if(location.getSpeed() > SPEED_TO_CHANGE) {
			    			toVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * OsmandSettings.getFastAutoVolume(settings) / 100;
			    		} else {
			    			toVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * OsmandSettings.getSlowAutoVolume(settings) / 100;
			    		}
			    		audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, toVolume, AudioManager.FLAG_PLAY_SOUND);
			    	}
				}
			}
		} catch (Exception e) {
		}
    	
    	locationLayer.setLastKnownLocation(location);
    	if(routingHelper.isFollowingMode()){
    		routingHelper.setCurrentLocation(location);
    	}
    	if (location != null) {
			if (isMapLinkedToLocation()) {
				if(OsmandSettings.isAutoZoomEnabled(settings) && location.hasSpeed()){
	    			int z = defineZoomFromSpeed(location.getSpeed(), mapView.getZoom());
	    			if(mapView.getZoom() != z && !mapView.mapIsAnimating()){
	    				long now = System.currentTimeMillis();
	    				// prevent ui hysterisis (check time interval for autozoom)
	    				if(Math.abs(mapView.getZoom() - z) > 1 || (lastTimeAutoZooming - now) > 6500){
	    					lastTimeAutoZooming = now;
	    					mapView.setZoom(z);
	    				}
	    			}
	    		}
				if (location.hasBearing() && currentMapRotation == OsmandSettings.ROTATE_MAP_BEARING) {
					mapView.setRotate(-location.getBearing());
				}
				mapView.setLatLon(location.getLatitude(), location.getLongitude());
			} else {
				if(backToLocation.getVisibility() != View.VISIBLE){
					backToLocation.setVisibility(View.VISIBLE);
				}
			}
		} else {
			if(backToLocation.getVisibility() != View.INVISIBLE){
				backToLocation.setVisibility(View.INVISIBLE);
			}
		}
    }
    
    public int defineZoomFromSpeed(float speed, int currentZoom){
    	speed *= 3.6;
    	if(speed < 4){
    		return currentZoom;
    	} else if(speed < 33){
    		// less than 33 - show 17 
    		return 17;
    	} else if(speed < 53){
    		return 16;
    	} else if(speed < 83){
    		return 15;
    	}
    	// more than 80 - show 14 (it is slow)
    	return 14;
    }

	public void navigateToPoint(LatLon point){
		if(point != null){
			OsmandSettings.setPointToNavigate(this, point.getLatitude(), point.getLongitude());
		} else {
			OsmandSettings.clearPointToNavigate(settings);
		}
		routingHelper.setFinalAndCurrentLocation(point, null, routingHelper.getCurrentGPXRoute());
		if(point == null){
			routingHelper.setFollowingMode(false);
			OsmandSettings.setFollowingByRoute(MapActivity.this, false);
		}
		navigationLayer.setPointToNavigate(point);
	}
	
	public Location getLastKnownLocation(){
		return locationLayer.getLastKnownLocation();
	}
	
	public LatLon getMapLocation(){
		return new LatLon(mapView.getLatitude(), mapView.getLongitude());
	}
	
	public LatLon getPointToNavigate(){
		return navigationLayer.getPointToNavigate();
	}
	
	public RoutingHelper getRoutingHelper() {
		return routingHelper;
	}
	
	private boolean isRunningOnEmulator(){
		if (Build.DEVICE.equals("generic")) { //$NON-NLS-1$ 
			return true;
		}  
		return false;
	}
	
	private boolean useOnlyGPS() {
		return (routingHelper != null && routingHelper.isFollowingMode())
				|| (System.currentTimeMillis() - lastTimeGPXLocationFixed) < USE_ONLY_GPS_INTERVAL || isRunningOnEmulator();
	}
    

	// Working with location listeners
	private LocationListener networkListener = new LocationListener(){
		
		@Override
		public void onLocationChanged(Location location) {
			// double check about use only gps
			// that strange situation but it could happen?
			if(!Algoritms.objectEquals(currentLocationProvider, LocationManager.GPS_PROVIDER) &&  
					!useOnlyGPS()){
				setLocation(location);
			}
		}

		@Override
		public void onProviderDisabled(String provider) {
			if(!useOnlyGPS()){
				setLocation(null);
			}
		}

		@Override
		public void onProviderEnabled(String provider) {
		}

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			if(LocationProvider.OUT_OF_SERVICE == status && !useOnlyGPS()){
				setLocation(null);
			}
		}
	};
	private LocationListener gpsListener = new LocationListener(){
		@Override
		public void onLocationChanged(Location location) {
			if (location != null) {
				lastTimeGPXLocationFixed = location.getTime();
			}
			setLocation(location);
		}

		@Override
		public void onProviderDisabled(String provider) {
			setLocation(null);
		}

		@Override
		public void onProviderEnabled(String provider) {
		}

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
			LocationProvider prov = service.getProvider(LocationManager.NETWORK_PROVIDER);
			// do not change provider for temporarily unavailable (possible bug for htc hero 2.1 ?)
			if (LocationProvider.OUT_OF_SERVICE == status /*|| LocationProvider.TEMPORARILY_UNAVAILABLE == status*/) {
				if(LocationProvider.OUT_OF_SERVICE == status){
					setLocation(null);
				}
				// do not use it in routing
				if (!useOnlyGPS() &&  
						service.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
					if (!Algoritms.objectEquals(currentLocationProvider, LocationManager.NETWORK_PROVIDER)) {
						currentLocationProvider = LocationManager.NETWORK_PROVIDER;
						service.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, GPS_TIMEOUT_REQUEST, GPS_DIST_REQUEST, this);
						providerSupportsBearing = prov == null ? false : prov.supportsBearing() && !isRunningOnEmulator();
						providerSupportsSpeed = prov == null ? false : prov.supportsSpeed() && !isRunningOnEmulator();
					}
				}
			} else if (LocationProvider.AVAILABLE == status) {
				if (!Algoritms.objectEquals(currentLocationProvider, LocationManager.GPS_PROVIDER)) {
					currentLocationProvider = LocationManager.GPS_PROVIDER;
					service.removeUpdates(networkListener);
					prov = service.getProvider(LocationManager.GPS_PROVIDER);
					providerSupportsBearing = prov == null ? false : prov.supportsBearing() && !isRunningOnEmulator();
					providerSupportsSpeed = prov == null ? false : prov.supportsSpeed() && !isRunningOnEmulator();
				}
			}

		}
	};
	
	

	
	@Override
	protected void onPause() {
		super.onPause();
		LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
		service.removeUpdates(gpsListener);
		service.removeUpdates(networkListener);
		
		SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
		sensorMgr.unregisterListener(this);
		sensorRegistered = false;
		currentLocationProvider = null;
		routingHelper.setUiActivity(null);
		
		((OsmandApplication)getApplication()).getDaynightHelper().onMapPause();
		
		OsmandSettings.setLastKnownMapLocation(this, (float) mapView.getLatitude(), (float) mapView.getLongitude());
		AnimateDraggingMapThread animatedThread = mapView.getAnimatedDraggingThread();
		if(animatedThread.isAnimating() && animatedThread.getTargetZoom() != 0){
			OsmandSettings.setMapLocationToShow(this, animatedThread.getTargetLatitude(), animatedThread.getTargetLongitude(), 
					animatedThread.getTargetZoom());
		}
		
		OsmandSettings.setLastKnownMapZoom(this, mapView.getZoom());
		if (wakeLock != null) {
			wakeLock.release();
			wakeLock = null;
		}
		OsmandSettings.setMapActivityEnabled(this, false);
		((OsmandApplication)getApplication()).getResourceManager().interruptRendering();
		((OsmandApplication)getApplication()).getResourceManager().setBusyIndicator(null);
	}
	
	private void updateApplicationModeSettings(){
		currentMapRotation = OsmandSettings.getRotateMap(settings);
		currentShowingAngle = OsmandSettings.isShowingViewAngle(settings);
		if(currentMapRotation == OsmandSettings.ROTATE_MAP_NONE){
			mapView.setRotate(0);
		}
		if(!currentShowingAngle){
			locationLayer.setHeading(null);
		}
		locationLayer.setAppMode(OsmandSettings.getApplicationMode(settings));
		routingHelper.setAppMode(OsmandSettings.getApplicationMode(settings));
		mapView.setMapPosition(OsmandSettings.getPositionOnMap(settings));
		registerUnregisterSensor(getLastKnownLocation());
		updateLayers();
	}
	
	private void updateLayers(){
		ArrayList<ITileSource> newSource = OsmandSettings.getMapTileOverlaySource(settings);
		mapOverlayLayer.setMapList(newSource);
		if(OsmandSettings.getMapTileOverlaySourceNameRaw(settings) != null) {
			overlayAlpha.setVisibility(android.view.View.VISIBLE);
			mapView.refreshMap();
		} else {
			overlayAlpha.setVisibility(android.view.View.GONE);
			mapView.refreshMap();
		}
		if(mapView.getLayers().contains(dsmWeatherLayer) != OsmandSettings.isShowingWeatherOverMap(settings)){
			if(OsmandSettings.isShowingWeatherOverMap(settings)){
				mapView.addLayer(dsmWeatherLayer, 0.53f);
				mapView.refreshMap();
			} else {
				mapView.removeLayer(dsmWeatherLayer);
			}
		}
		if(mapView.getLayers().contains(dsmMapLayer) != OsmandSettings.isShowingDualsportmapsOverMap(settings)){
			if(OsmandSettings.isShowingDualsportmapsOverMap(settings)){
				mapView.addLayer(dsmMapLayer, 0.55f);
				mapView.refreshMap();
			} else {
				mapView.removeLayer(dsmMapLayer);
			}
		}

		if(mapView.getLayers().contains(dsmActiveLogLayer) != OsmandSettings.isShowingDualsportmapsOverMap(settings)){
			if(OsmandSettings.isSavingTrackToGpx(this) || ((OsmandApplication)this.getApplication()).getNavigationService() != null) {
				mapView.addLayer(dsmActiveLogLayer, 0.75f);
				mapView.refreshMap();
			} else {
				mapView.removeLayer(dsmActiveLogLayer);
			}
		}
		
		if(mapView.getLayers().contains(dsmAppUserLocationLayer) != OsmandSettings.isShowingDualsportmapsUserLocation(settings)){
			if(OsmandSettings.isShowingDualsportmapsUserLocation(settings)) {
				mapView.addLayer(dsmAppUserLocationLayer, 0.80f);
				mapView.refreshMap();
			} else {
				mapView.removeLayer(dsmAppUserLocationLayer);
			}
		}
		
		if(mapView.getLayers().contains(dsmUtmLayer) != OsmandSettings.isShowingUTMOverMap(settings)){
			if(OsmandSettings.isShowingUTMOverMap(settings)) {
				mapView.addLayer(dsmUtmLayer, .85f);
				mapView.refreshMap();
			} else {
				mapView.removeLayer(dsmUtmLayer);
			}
		}
		
		if(mapView.getLayers().contains(poiMapLayer) != OsmandSettings.isShowingPoiOverMap(settings)){
			if(OsmandSettings.isShowingPoiOverMap(settings)){
				mapView.addLayer(poiMapLayer, 3);
			} else {
				mapView.removeLayer(poiMapLayer);
			}
		}
		
		if(mapView.getLayers().contains(favoritesLayer) != OsmandSettings.isShowingFavorites(settings)){
			if(OsmandSettings.isShowingFavorites(settings)){
				mapView.addLayer(favoritesLayer, 4);
			} else {
				mapView.removeLayer(favoritesLayer);
			}
		}
		if(mapView.getLayers().contains(trafficLayer) != OsmandSettings.isShowingYandexTraffic(settings)){
			if(OsmandSettings.isShowingYandexTraffic(settings)){
				mapView.addLayer(trafficLayer, 1.5f);
			} else {
				mapView.removeLayer(trafficLayer);				
			}
		}		
	}
	
	private void updateMapSource(){
		boolean vectorData = OsmandSettings.isUsingMapVectorData(settings);
		OsmandApplication app = ((OsmandApplication)getApplication());
		ResourceManager rm = app.getResourceManager();
		if(vectorData && !app.isApplicationInitializing()){
			if(rm.getRenderer().isEmpty()){
				Toast.makeText(MapActivity.this, getString(R.string.no_vector_map_loaded), Toast.LENGTH_LONG).show();
				vectorData = false;
			}
		}
		ITileSource newSource = OsmandSettings.getMapTileSource(settings);
		if(mapView.getMap() instanceof SQLiteTileSource){
			((SQLiteTileSource)mapView.getMap()).closeDB();
		}
		rm.updateMapSource(vectorData, newSource);
		
		mapView.setMap(vectorData ? null : newSource);
		ZoomControls zoomControls = (ZoomControls) findViewById(R.id.ZoomControls);
		zoomControls.setIsZoomInEnabled(mapView.getZoom() + 1 < mapView.getMaximumShownMapZoom());
		zoomControls.setIsZoomOutEnabled(mapView.getZoom() + 1 > mapView.getMinimumShownMapZoom());
		rendererLayer.setVisible(vectorData);
	}
	
	
	@Override
	protected void onResume() {
		super.onResume();
		DsmResourceManager.getDsmResourceManager((OsmandApplication)getApplication()).setMapActivity(this);
		if(OsmandSettings.getMapOrientation(settings) != getRequestedOrientation()){
			setRequestedOrientation(OsmandSettings.getMapOrientation(settings));
			// can't return from this method we are not sure if activity will be recreated or not
		}
		currentScreenOrientation = getWindow().getWindowManager().getDefaultDisplay().getOrientation();
		boolean showTiles = !OsmandSettings.isUsingMapVectorData(settings);
		ITileSource source = showTiles ? OsmandSettings.getMapTileSource(settings) : null;
		if (showTiles != !rendererLayer.isVisible() || !Algoritms.objectEquals(mapView.getMap(), source)) {
			updateMapSource();
		}
		
		updateApplicationModeSettings();
		

		poiMapLayer.setFilter(OsmandSettings.getPoiFilterForMap(this, (OsmandApplication) getApplication()));
		backToLocation.setVisibility(View.INVISIBLE);
		
		routingHelper.setUiActivity(this);

		
		LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
		try {
			service.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_TIMEOUT_REQUEST, GPS_DIST_REQUEST, gpsListener);
			currentLocationProvider = LocationManager.GPS_PROVIDER;
		} catch (IllegalArgumentException e) {
			Log.d(LogUtil.TAG, "GPS location provider not available"); //$NON-NLS-1$
		}
		if(!useOnlyGPS()){
			// try to always  ask for network provide : it is faster way to find location
			try {
				service.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, GPS_TIMEOUT_REQUEST, GPS_DIST_REQUEST, networkListener);
				currentLocationProvider = LocationManager.NETWORK_PROVIDER;
			} catch(IllegalArgumentException e) {
				Log.d(LogUtil.TAG, "Network location provider not available"); //$NON-NLS-1$
			}
		}
		
		LocationProvider  prov = service.getProvider(currentLocationProvider); 
		providerSupportsBearing = prov == null ? false : prov.supportsBearing() && !isRunningOnEmulator();
		providerSupportsSpeed = prov == null ? false : prov.supportsSpeed() && !isRunningOnEmulator();
		
		if(settings != null && settings.contains(OsmandSettings.LAST_KNOWN_MAP_LAT)){
			LatLon l = OsmandSettings.getLastKnownMapLocation(settings);
			mapView.setLatLon(l.getLatitude(), l.getLongitude());
			mapView.setZoom(OsmandSettings.getLastKnownMapZoom(settings));
		}
		
		
		if (wakeLock == null) {
			PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
			wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "net.osmand.map"); //$NON-NLS-1$
			wakeLock.acquire();
		}
		
		OsmandSettings.setMapActivityEnabled(this, true);
		checkExternalStorage();
		showAndHideMapPosition();
		
		LatLon latLon = OsmandSettings.getAndClearMapLocationToShow(settings);
		LatLon cur = new LatLon(mapView.getLatitude(), mapView.getLongitude());
		if (latLon != null && !latLon.equals(cur)) {
			mapView.getAnimatedDraggingThread().startMoving(cur.getLatitude(), cur.getLongitude(), latLon.getLatitude(),
					latLon.getLongitude(), mapView.getZoom(), OsmandSettings.getMapZoomToShow(settings), mapView.getSourceTileSize(),
					mapView.getRotate(), true);
		}
		
		View progress = findViewById(R.id.ProgressBar);
		if(progress != null){
			((OsmandApplication) getApplication()).getResourceManager().setBusyIndicator(new BusyIndicator(this, progress));
		}
		((OsmandApplication)getApplication()).getDaynightHelper().onMapResume();
	}
	
	
	public void checkExternalStorage(){
		String state = Environment.getExternalStorageState();
		if(Environment.MEDIA_MOUNTED.equals(state)){
			// ok
		} else if(Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)){
			Toast.makeText(this, R.string.sd_mounted_ro, Toast.LENGTH_LONG).show();
		} else {
			Toast.makeText(this, R.string.sd_unmounted, Toast.LENGTH_LONG).show();
		}
	}
	
	
	public void showAndHideMapPosition(){
		mapView.setShowMapPosition(true);
		if(mapPositionHandler == null){
			mapPositionHandler = new Handler();
		}
		Message msg = Message.obtain(mapPositionHandler, new Runnable(){
			@Override
			public void run() {
				if(mapView.isShowMapPosition()){
					mapView.setShowMapPosition(false);
					mapView.refreshMap();
				}
			}
			
		});
		msg.what = 7;
		mapPositionHandler.removeMessages(7);
		mapPositionHandler.sendMessageDelayed(msg, 2500);
		
	}
	
	

	@Override
	public void locationChanged(double newLatitude, double newLongitude, Object source) {
		// when user start dragging 
		if(locationLayer.getLastKnownLocation() != null){
			if(isMapLinkedToLocation()){
				OsmandSettings.setSyncMapToGpsLocation(MapActivity.this, false);
			}
			if (backToLocation.getVisibility() != View.VISIBLE) {
				runOnUiThread(new Runnable() {
					@Override
					public void run() {
						backToLocation.setVisibility(View.VISIBLE);
					}
				});
			}
		}
	}
	
	public void setMapLocation(double lat, double lon){
		mapView.setLatLon(lat, lon);
		locationChanged(lat, lon, this);
	}
	
	public OsmandMapTileView getMapView() {
		return mapView;
	}
	
	@Override
	public void onSensorChanged(SensorEvent event) {
		// Attention : sensor produces a lot of events & can hang the system
		float val = event.values[0];
		if(currentScreenOrientation == 1){
			val += 90;
		}
		if (currentMapRotation == OsmandSettings.ROTATE_MAP_COMPASS) {
			mapView.setRotate(-val);
		}
		if(currentShowingAngle){
			if(locationLayer.getHeading() == null || Math.abs(locationLayer.getHeading() - val) > 10){
				locationLayer.setHeading(val);
			}
		}
		
	}
	
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.map_menu, menu);
		return true;
	}
	
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		boolean val = super.onPrepareOptionsMenu(menu);
		MenuItem navigateToPointMenu = menu.findItem(R.id.map_navigate_to_point);
		if (navigateToPointMenu != null) {
			navigateToPointMenu.setTitle(routingHelper.isRouteCalculated() ? R.string.stop_routing : R.string.stop_navigation);
			if (OsmandSettings.getPointToNavigate(settings) != null) {
				navigateToPointMenu.setVisible(true);
			} else {
				navigateToPointMenu.setVisible(false);
			}
		}
		MenuItem muteMenu = menu.findItem(R.id.map_mute); 
		if(muteMenu != null){
			muteMenu.setTitle(routingHelper.getVoiceRouter().isMute() ? R.string.menu_mute_on : R.string.menu_mute_off);
			if (routingHelper.getFinalLocation() != null && routingHelper.isFollowingMode()) {
				muteMenu.setVisible(true);
			} else {
				muteMenu.setVisible(false);
			}
		}
		
		return val;
	}
	
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == R.id.map_show_settings) {
    		final Intent settings = new Intent(MapActivity.this, SettingsActivity.class);
			startActivity(settings);
    		return true;
		} else if (item.getItemId() == R.id.map_where_am_i) {
			backToLocationImpl();
        	return true;
		} else if (item.getItemId() == R.id.map_show_gps_status) {
			Intent intent = new Intent();
			intent.setComponent(new ComponentName(GPS_STATUS_COMPONENT, GPS_STATUS_ACTIVITY));
			ResolveInfo resolved = getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
			if(resolved != null){
				startActivity(intent);
			} else {
				AlertDialog.Builder builder = new AlertDialog.Builder(this);
				builder.setMessage(getString(R.string.gps_status_app_not_found));
				builder.setPositiveButton(getString(R.string.default_buttons_yes),
						new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int which) {
								Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:" + GPS_STATUS_COMPONENT));
								try {
									startActivity(intent);
								} catch (ActivityNotFoundException e) {
								}
							}
						});
				builder.setNegativeButton(getString(R.string.default_buttons_no), null);
				builder.show();
			}
			return true;
//		} else if (item.getItemId() == R.id.map_mark_point) {
//			contextMenuPoint(mapView.getLatitude(), mapView.getLongitude());
//			return true;
		} else if (item.getItemId() == R.id.map_get_directions) {
			getDirections(mapView.getLatitude(), mapView.getLongitude(), true);
			return true;
		} else if (item.getItemId() == R.id.map_layers) {
			openLayerSelectionDialog();
			return true;
		} else if (item.getItemId() == R.id.map_specify_point) {
			NavigatePointActivity dlg = new NavigatePointActivity(this);
			dlg.showDialog();
			return true;
		} else if (item.getItemId() == R.id.dsm_map_search) {
			dsmMapSearch();
			return true;
    	} else if (item.getItemId() == R.id.map_mute) {
			routingHelper.getVoiceRouter().setMute(!routingHelper.getVoiceRouter().isMute());
			return true;
    	}  else if (item.getItemId() == R.id.map_navigate_to_point) {
    		if(navigationLayer.getPointToNavigate() != null){
    			if(routingHelper.isRouteCalculated()){
    				routingHelper.setFinalAndCurrentLocation(null, null);
    				OsmandSettings.setFollowingByRoute(MapActivity.this, false);
    				routingHelper.setFollowingMode(false);
    			} else {
    				navigateToPoint(null);
    			}
    		} else {
    			navigateToPoint(new LatLon(mapView.getLatitude(), mapView.getLongitude()));
    		}
			mapView.refreshMap();
    	} else if (item.getItemId() == R.id.map_gpx_load) {
    		useGPXFile(false, null);
			return true;
    	} else if (item.getItemId() == R.id.map_gpx_routing) {
    		useGPXFile(true, navigationLayer.getPointToNavigate());
			return true;
    	} else if (item.getItemId() == R.id.map_show_point_options) {
			contextMenuPoint(mapView.getLatitude(), mapView.getLongitude());
    		return true;
    	}
    	return super.onOptionsItemSelected(item);
    }
    
    private ApplicationMode getAppMode(ToggleButton[] buttons){
    	for(int i=0; i<buttons.length; i++){
    		if(buttons[i] != null && buttons[i].isChecked() && i < ApplicationMode.values().length){
    			if(i==0)
    				return ApplicationMode.CAR;
    			else if(i==1)
    				return ApplicationMode.BICYCLE;
    			else if(i==2)
    				return ApplicationMode.PEDESTRIAN;
    		}
    	}
    	return ApplicationMode.CAR;
    }
    
    public void getDirectionsFromCurrentLocation() {
    	if(getLastKnownLocation() != null)
    		getDirections(getLastKnownLocation().getLatitude(),getLastKnownLocation().getLongitude(),true);
    	else
    		Toast.makeText(this, "Current Location Unknown", Toast.LENGTH_LONG).show();
    }
    
    protected void getDirections(final double lat, final double lon, boolean followEnabled){
    	if(navigationLayer.getPointToNavigate() == null){
			Toast.makeText(this, R.string.mark_final_location_first, Toast.LENGTH_LONG).show();
			return;
		}
    	Builder builder = new AlertDialog.Builder(this);
    	
    	View view = getLayoutInflater().inflate(R.layout.calculate_route, null);
    	final ToggleButton[] buttons = new ToggleButton[3];
    	buttons[0] = (ToggleButton) view.findViewById(R.id.CarButton);
    	buttons[1] = (ToggleButton) view.findViewById(R.id.BicycleButton);
    	buttons[2] = (ToggleButton) view.findViewById(R.id.PedestrianButton);
    	for(int i=0; i< buttons.length; i++){
    		if(buttons[i] != null){
    			final int ind = i;
    			ToggleButton b = buttons[i];
    			b.setChecked(i==0);
    			b.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
					@Override
					public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
						if(isChecked){
							for (int j = 0; j < buttons.length; j++) {
								if (buttons[j] != null) {
									if(buttons[j].isChecked() != (ind == j)){
										buttons[j].setChecked(ind == j);
									}
								}
							}
						} else {
							// revert state
							boolean revert = true;
							for (int j = 0; j < buttons.length; j++) {
								if (buttons[j] != null) {
									if(buttons[j].isChecked()){
										revert = false;
										break;
									}
								}
							}
							if (revert){ 
								buttons[ind].setChecked(true);
							}
						}
					}
    			});
    		}
    	}
    	
    	DialogInterface.OnClickListener onlyShowCall = new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface dialog, int which) {
				ApplicationMode mode = getAppMode(buttons);
				Location map = new Location("map"); //$NON-NLS-1$
				map.setLatitude(lat);
				map.setLongitude(lon);
				routingHelper.setAppMode(mode);
				OsmandSettings.setFollowingByRoute(MapActivity.this, false);
				routingHelper.setFollowingMode(false);
				routingHelper.setFinalAndCurrentLocation(navigationLayer.getPointToNavigate(), map);
			}
    	};
    	
    	DialogInterface.OnClickListener followCall = new DialogInterface.OnClickListener(){
			@Override
			public void onClick(DialogInterface dialog, int which) {
				ApplicationMode mode = getAppMode(buttons);
				// change global settings
				ApplicationMode old = OsmandSettings.getApplicationMode(settings);
				if (old != mode) {
					Editor edit = getSharedPreferences(OsmandSettings.SHARED_PREFERENCES_NAME, MODE_WORLD_WRITEABLE).edit();
					edit.putString(OsmandSettings.APPLICATION_MODE, mode.name());
					SettingsActivity.setAppMode(mode, edit, (OsmandApplication) getApplication(), old);
					edit.commit();
					updateApplicationModeSettings();	
					mapView.refreshMap();
				}
				
				Location location = locationLayer.getLastKnownLocation();
				if(location == null){
					location = new Location("map"); //$NON-NLS-1$
					location.setLatitude(lat);
					location.setLongitude(lon);
				} 
				routingHelper.setAppMode(mode);
				OsmandSettings.setFollowingByRoute(MapActivity.this, true);
				routingHelper.setFollowingMode(true);
				routingHelper.setFinalAndCurrentLocation(navigationLayer.getPointToNavigate(), location);
				
				((OsmandApplication) getApplication()).showDialogInitializingCommandPlayer(MapActivity.this);
				
			}
    	};
    	DialogInterface.OnClickListener showRoute = new DialogInterface.OnClickListener(){
			@Override
			public void onClick(DialogInterface dialog, int which) {
				Intent intent = new Intent(MapActivity.this, ShowRouteInfoActivity.class);
				intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
				startActivity(intent);
			}
		};
    	
    	builder.setView(view);
    	if (followEnabled) {
    		builder.setTitle(R.string.follow_route);
			builder.setPositiveButton(R.string.follow, followCall);
			if (routingHelper.isRouterEnabled() && routingHelper.isRouteCalculated()) {
				builder.setNeutralButton(R.string.route_about, showRoute);
			}
			builder.setNegativeButton(R.string.only_show, onlyShowCall);
		} else {
			builder.setTitle(R.string.show_route);
			view.findViewById(R.id.TextView).setVisibility(View.GONE);
    		builder.setPositiveButton(R.string.show_route, onlyShowCall);
    		builder.setNegativeButton(R.string.default_buttons_cancel, null);
    	}
    	builder.show();
    }
    
    
    
    
    protected void parseLaunchIntentLocation(){
    	Intent intent = getIntent();
    	if(intent != null && intent.getData() != null){
    		Uri data = intent.getData();
    		if("http".equalsIgnoreCase(data.getScheme()) && "www.dualsportmaps.com".equals(data.getHost()) &&
    				"/go".equals( data.getPath())) {
    			String lat = data.getQueryParameter("lat");
    			String lon = data.getQueryParameter("lon");
				if (lat != null && lon != null) {
					try {
						double lt = Double.parseDouble(lat);
						double ln = Double.parseDouble(lon);
						SharedPreferences prefs = OsmandSettings.getSharedPreferences(this);
						Editor edit = prefs.edit();
						edit.putFloat(OsmandSettings.LAST_KNOWN_MAP_LAT, (float) lt);
						edit.putFloat(OsmandSettings.LAST_KNOWN_MAP_LON, (float) ln);
						String zoom = data.getQueryParameter("z");
						if(zoom != null){
							edit.putInt(OsmandSettings.LAST_KNOWN_MAP_ZOOM, Integer.parseInt(zoom));
						}
						edit.commit();
					} catch (NumberFormatException e) {
					}
				}
//				else {
//					backToLocationImpl();
//				}
    		}
    	}
    }
    
    protected boolean parseLaunchIntentFile() {
    	boolean retval = false;
    	Intent intent = getIntent();
    	if(intent != null && intent.getData() != null){
    		Uri data = intent.getData();
    		final File dir = OsmandSettings.extendOsmandPath(getApplicationContext(), ResourceManager.APP_DIR + SavingTrackHelper.TRACKS_PATH);
    		File gpxFile = new File(dir,"import.gpx");
    		if(gpxFile.exists()) {
    			gpxFile.delete();
    		}
    		if(data.getScheme().equals("content")) {
    			try {
    				String name = Utils.getContentName(getContentResolver(), data);
    				if(!name.toLowerCase().endsWith("gpx")) {
    					finish();
    				}
					BufferedInputStream bis = new BufferedInputStream(getContentResolver().openInputStream(data));    			
					OutputStream out = new FileOutputStream(gpxFile);
					byte buf[]=new byte[1024];
					int len;
					while((len=bis.read(buf))>0)
						out.write(buf,0,len);
					bis.close();
					out.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
    		} else if(data.getScheme().equals("file")) {
    			try {
					gpxFile = new File(new URI(data.toString()));
				} catch (URISyntaxException e) {
					e.printStackTrace();
				}
    		}
    		retval = loadGPXFile(gpxFile);
    	}
    	return retval;
    }
    
    public boolean gpxFileLoaded(String dsmMapId) {
    	if(!dsmMapId.equals("error")) {
    		try {
    			final DsmMapDownload gpxMap = new DsmMapDownload(dsmMapId);
				if(gpxMap != null) {
					DsmResourceManager.getDsmResourceManager((OsmandApplication)getApplication()).showDsmMap(gpxMap);
					setDsmMapDownloadViewable(gpxMap);
					//MOVE MAP
					LatLon latLon = OsmandSettings.getAndClearMapLocationToShow(settings);
					LatLon cur = new LatLon(mapView.getLatitude(), mapView.getLongitude());
					if (latLon != null && !latLon.equals(cur)) {
						mapView.getAnimatedDraggingThread().startMoving(cur.getLatitude(), cur.getLongitude(), latLon.getLatitude(),
								latLon.getLongitude(), mapView.getZoom(), OsmandSettings.getMapZoomToShow(settings), mapView.getSourceTileSize(),
								mapView.getRotate(), true);
					}					
					this.runOnUiThread(new Runnable() {
	
						@Override
						public void run() {
							
		    				Context mContext = getApplicationContext();
							final Dialog  dlg = new Dialog(MapActivity.this, R.style.Theme_TransparentDialog);
		    				LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);
		    				View layout = inflater.inflate(R.layout.new_gpx_dialog, null);
		    				dlg.addContentView(layout, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
		    				dlg.setTitle("GPX File Processed");
		    				final EditText text = (EditText) layout.findViewById(R.id.new_gpx_name);
		    				Button button = (Button) layout.findViewById(R.id.new_gpx_button);
		    				button.setOnClickListener(new OnClickListener() {
								@Override
								public void onClick(View v) {
									if(text.getText().length() > 0) {
										gpxMap.getMap().setDsmMapName(text.getText().toString());
										DsmMapDownload.saveDsmMap(gpxMap, MapActivity.this);
										dlg.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
										dlg.dismiss();										
									} else {
										Toast.makeText(MapActivity.this, "You must enter a map name.", Toast.LENGTH_LONG).show();
									}
								}});
		    				if(gpxMap.getMap().getDsmMapName().endsWith(".gpx")) {
			    				dlg.show();
			    				dlg.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
		    				}
						}});							
				}
				return true;
			} catch (final Exception e) {
				e.printStackTrace();
				this.runOnUiThread(new Runnable() {
	
					@Override
					public void run() {
						Builder builder = new AlertDialog.Builder(MapActivity.this);
						builder.setMessage("Your GPX file failed to convert.\n" + e.getMessage());
						builder.setTitle("GPX File Error");
						builder.show().show();
					}});
			}
		} else {
			this.runOnUiThread(new Runnable() {

				@Override
				public void run() {
					Builder builder = new AlertDialog.Builder(MapActivity.this);
					builder.setMessage("Your GPX file failed to convert.");
					builder.setTitle("GPX File Error");
					builder.show().show();
				}});
		}
    	return false;
    }
    
    private boolean loadGPXFile(File gpxFile) {
		boolean retval = false;
    	if(gpxFile.exists()) {
    			try {
					if(gpxFile.length() < 1500000) {
						DsmResourceManager.getDsmResourceManager().asyncLoader.requestToProcessGPX(new GPXProcessRequest(gpxFile));	
						Toast.makeText(this, "GPX File Loading", Toast.LENGTH_LONG).show();
					} else {
						this.runOnUiThread(new Runnable() {

							@Override
							public void run() {
								Builder builder = new AlertDialog.Builder(MapActivity.this);
								builder.setMessage("Your GPX file is too large. Please upload it at www.dualsportmaps.com and then download it the normal way.");
								builder.setTitle("GPX File Error");
								builder.show();
							}});
						
					}
				} catch (DsmResourceManagerException e) {
					Toast.makeText(this, "GPX Error", Toast.LENGTH_LONG).show();
					e.printStackTrace();
				}
		}
    	return retval;
    }
    
    public void setDsmMapDownloadViewable(final DsmMapDownload map) {
    		try {
    			setDsmMapDownloadViewable(map.getMap().getDsmMapName(),map.getMapCenter().getLatitude(),map.getMapCenter().getLongitude(),map.getMap().getDsmMapBound1Lat(),map.getMap().getDsmMapBound1Lng(),map.getMap().getDsmMapBound2Lat(),map.getMap().getDsmMapBound2Lng());
    		} catch (Exception e) {
				e.printStackTrace();
			}
    }
    
    public void setDsmMapDownloadViewable(final String zoomDesc, final double centerLat, final double centerLng, final double bnd1Lat, final double bnd1Lng,final double bnd2Lat, final double bnd2Lng) {
		this.runOnUiThread(new Runnable() {
			@Override
			public void run() {
				try {
					float maxDim = (float) Math.max(Math.abs(bnd1Lat-bnd2Lat),Math.abs(bnd1Lng-bnd2Lng));
					int zoom = 6;
					if(maxDim>1.5)
						zoom = 7;
					else if(maxDim>0.8)
						zoom = 8;
					else if(maxDim>0.6)
						zoom = 9;
					else if(maxDim>0.4)
						zoom = 10;
					else if(maxDim>0.3)
						zoom = 11;
					else if(maxDim>0.2)
						zoom = 12;
					else if(maxDim<=0.2)
						zoom = 13;
					OsmandSettings.setMapLocationToShow(MapActivity.this, centerLat,centerLng,zoom,"Map " + zoomDesc + " Selected");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
}
	private void openLayerSelectionDialog(){
		List<String> layersList = new ArrayList<String>();
		layersList.add(getString(R.string.layer_map));
		layersList.add(getString(R.string.layer_map_overlay));
		layersList.add(getString(R.string.layer_dsm));
		layersList.add(getString(R.string.layer_user_location));
		layersList.add(getString(R.string.layer_utm));
		layersList.add(getString(R.string.layer_weather));
		layersList.add(getString(R.string.layer_traffic));
		layersList.add(getString(R.string.layer_poi));
		layersList.add(getString(R.string.layer_favorites));
		final int routeInfoInd = routeInfoLayer.couldBeVisible() ? layersList.size() : -1;
		if(routeInfoLayer.couldBeVisible()){
			layersList.add(getString(R.string.layer_route));
		}
		
		final boolean[] selected = new boolean[layersList.size()];
		Arrays.fill(selected, true);
		selected[1] = OsmandSettings.getMapTileOverlaySourceNameRaw(settings) != null;
		selected[2] = OsmandSettings.isShowingDualsportmapsOverMap(settings);
		selected[3] = OsmandSettings.isShowingDualsportmapsUserLocation(settings);
		selected[4] = OsmandSettings.isShowingUTMOverMap(settings);
		selected[5] = OsmandSettings.isShowingWeatherOverMap(settings);
		selected[6] = OsmandSettings.isShowingYandexTraffic(settings);
		selected[7] = OsmandSettings.isShowingPoiOverMap(settings);
		selected[8] = OsmandSettings.isShowingFavorites(settings);
		if(routeInfoInd != -1){
			selected[routeInfoInd] = routeInfoLayer.isUserDefinedVisible(); 
		}
		
		Builder builder = new AlertDialog.Builder(this);
		builder.setMultiChoiceItems(layersList.toArray(new String[layersList.size()]), selected, new DialogInterface.OnMultiChoiceClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int item, boolean isChecked) {
				if (item == 0) {
					dialog.dismiss();
					selectMapLayer();
				} else if(item == 1){
					dialog.dismiss();
					selectMapTileOverlayLayer();
				} else if(item == 2){
					OsmandSettings.setShowDualsportmapsOverMap(MapActivity.this, isChecked);
				} else if(item == 3){
					OsmandSettings.setShowDualsportmapsUserLocation(MapActivity.this, isChecked);
				} else if(item == 4){
					OsmandSettings.setShowUTMOverMap(MapActivity.this, isChecked);
				} else if(item == 5){
					OsmandSettings.setShowWeatherOverMap(MapActivity.this, isChecked);
				} else if(item == 6){
					OsmandSettings.setShowingYandexTraffic(MapActivity.this, isChecked);
				} else if(item == 7){
					if(isChecked){
						selectPOIFilterLayer();
					}
					OsmandSettings.setShowPoiOverMap(MapActivity.this, isChecked);
				} else if(item == 8){
					OsmandSettings.setShowingFavorites(MapActivity.this, isChecked);
				} else if(item == routeInfoInd){
					routeInfoLayer.setVisible(isChecked);
				} 
				updateLayers();
				mapView.refreshMap();
			}
		});
		builder.show();
	}
	
	private void useGPXFile(final boolean useRouting, final LatLon endForRouting) {
		final List<String> list = new ArrayList<String>();
		final File dir = OsmandSettings.extendOsmandPath(getApplicationContext(), ResourceManager.APP_DIR + SavingTrackHelper.TRACKS_PATH);
		if (dir != null && dir.canRead()) {
			File[] files = dir.listFiles();
			if (files != null) {
				Arrays.sort(files, new Comparator<File>() {
					@Override
					public int compare(File object1, File object2) {
						if (object1.lastModified() > object2.lastModified()) {
							return -1;
						} else if (object1.lastModified() == object2.lastModified()) {
							return 0;
						}
						return 1;
					}

				});

				for (File f : files) {
					if (f.getName().toLowerCase().endsWith(".gpx")) { 
						list.add(f.getName());
					}
				}
			}
		}
		
		if(list.isEmpty()){
			Toast.makeText(this, R.string.gpx_files_not_found, Toast.LENGTH_LONG).show();
		} else {
			Builder builder = new AlertDialog.Builder(this);
			builder.setItems(list.toArray(new String[list.size()]), new DialogInterface.OnClickListener() {

				@Override
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
					final File f = new File(dir, list.get(which));
					loadGPXFile(f);
				}

			});
			builder.show();
		}
		
	}
	
	public FavouritesDbHelper getFavoritesHelper() {
		return ((OsmandApplication)getApplication()).getFavorites();
	}
	
	//TODO I want to use this feature for all DSM maps
	@SuppressWarnings("unused")
	private void useGPXRouting(final LatLon endForRouting, final GPXFileResult res) {
		Builder builder = new AlertDialog.Builder(this);
		builder.setItems(new String[]{getString(R.string.gpx_direct_route), getString(R.string.gpx_reverse_route)}, 
				new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				boolean reverse = which == 1;
				ArrayList<List<Location>> locations = res.locations;
				List<Location> l = new ArrayList<Location>();
				for(List<Location> s : locations){
					l.addAll(s);
				}
				if(reverse){
					Collections.reverse(l);
				}
				Location startForRouting = locationLayer.getLastKnownLocation();
				if(startForRouting == null && !l.isEmpty()){
					startForRouting = l.get(0);
				}
				LatLon endPoint = endForRouting;
				if(/*endForRouting == null && */!l.isEmpty()){
					LatLon point = new LatLon(l.get(l.size() - 1).getLatitude(), l.get(l.size() - 1).getLongitude());
					OsmandSettings.setPointToNavigate(MapActivity.this, point.getLatitude(), point.getLongitude());
					endPoint = point;
					navigationLayer.setPointToNavigate(point);
				}
				if(endForRouting != null){
					OsmandSettings.setFollowingByRoute(MapActivity.this, true);
					routingHelper.setFollowingMode(true);
					routingHelper.setFinalAndCurrentLocation(endPoint, startForRouting, l);
					((OsmandApplication)getApplication()).showDialogInitializingCommandPlayer(MapActivity.this);
				}
				
			}
		
		});
		builder.show();
	}
		
	private void selectPOIFilterLayer(){
		final List<PoiFilter> userDefined = new ArrayList<PoiFilter>();
		List<String> list = new ArrayList<String>();
		list.add(getString(R.string.any_poi));
		
		final PoiFiltersHelper poiFilters = ((OsmandApplication)getApplication()).getPoiFilters();
		for (PoiFilter f : poiFilters.getUserDefinedPoiFilters()) {
			userDefined.add(f);
			list.add(f.getName());
		}
		for(AmenityType t : AmenityType.values()){
			list.add(OsmAndFormatter.toPublicString(t, this));
		}
		Builder builder = new AlertDialog.Builder(this);
		builder.setItems(list.toArray(new String[list.size()]), new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface dialog, int which) {
				String filterId;
				if (which == 0) {
					filterId = PoiFiltersHelper.getOsmDefinedFilterId(null);
				} else if (which <= userDefined.size()) {
					filterId = userDefined.get(which - 1).getFilterId();
				} else {
					filterId = PoiFiltersHelper.getOsmDefinedFilterId(AmenityType.values()[which - userDefined.size() - 1]);
				}
				if(filterId.equals(PoiFilter.CUSTOM_FILTER_ID)){
					Intent newIntent = new Intent(MapActivity.this, EditPOIFilterActivity.class);
					newIntent.putExtra(EditPOIFilterActivity.AMENITY_FILTER, filterId);
					newIntent.putExtra(EditPOIFilterActivity.SEARCH_LAT, mapView.getLatitude());
					newIntent.putExtra(EditPOIFilterActivity.SEARCH_LON, mapView.getLongitude());
					startActivity(newIntent);
				} else {
					OsmandSettings.setPoiFilterForMap(MapActivity.this, filterId);
					poiMapLayer.setFilter(poiFilters.getFilterById(filterId));
					mapView.refreshMap();
				}
			}
			
		});
		builder.show();
	}
	
	private void selectMapLayer(){
		Map<String, String> entriesMap = SettingsActivity.getTileSourceEntries(this);
		Builder builder = new AlertDialog.Builder(this);
		final ArrayList<String> keys = new ArrayList<String>(entriesMap.keySet());
		String[] items = new String[entriesMap.size() + 1];
		items[0] = getString(R.string.vector_data);
		int i = 1;
		for(String it : entriesMap.values()){
			items[i++] = it;
		}
		builder.setItems(items, new DialogInterface.OnClickListener(){
			@Override
			public void onClick(DialogInterface dialog, int which) {
				Editor edit = OsmandSettings.getWriteableEditor(MapActivity.this);
				if(which == 0){
					MapRenderRepositories r = ((OsmandApplication)getApplication()).getResourceManager().getRenderer();
					if(r.isEmpty()){
						Toast.makeText(MapActivity.this, getString(R.string.no_vector_map_loaded), Toast.LENGTH_LONG).show();
						return;
					} else {
						edit.putBoolean(OsmandSettings.MAP_VECTOR_DATA, true);
					}
				} else {
					edit.putBoolean(OsmandSettings.MAP_VECTOR_DATA, false);
					edit.putString(OsmandSettings.MAP_TILE_SOURCES, keys.get(which - 1));
				}
				edit.commit();
				updateMapSource();
			}
			
		});
		builder.show();
	}

	private void selectMapTileOverlayLayer() {
		Map<String, String> entriesMap = SettingsActivity.getTileOverlaySourceEntries(this);
		if(entriesMap.values().size() == 0) {
			Builder builder = new AlertDialog.Builder(this);
			builder.setMessage("Would you like to download map overlays now?");
			builder.setPositiveButton("Download Map Overlays", new DialogInterface.OnClickListener() {

				@Override
				public void onClick(DialogInterface dialog, int which) {
					startActivity(new Intent(MapActivity.this, DsmMapTileOverlayDownloadActivity.class));
				}

			});
			builder.setNegativeButton(R.string.first_time_continue, null);
			builder.show();
		} else {
			Builder builder = new AlertDialog.Builder(this);
			final ArrayList<String> keys = new ArrayList<String>(entriesMap.keySet());
			String[] items = new String[entriesMap.size() + 1];
			items[0] = "No Overlay";
			boolean[] selected = new boolean[entriesMap.size() + 1];
			selected[0] = false;
			int i = 1;
			List<String> selectedMaps = Arrays.asList(OsmandSettings.getMapTileOverlaySourceName(settings));
			for(String it : entriesMap.keySet()){
				items[i] = entriesMap.get(it);
				selected[i++] = selectedMaps.contains(it);
			}
			builder.setMultiChoiceItems(items,selected, new DialogInterface.OnMultiChoiceClickListener(){
				@Override
				public void onClick(DialogInterface dialog, int which, boolean selected) {
					Editor edit = OsmandSettings.getWriteableEditor(MapActivity.this);
					if(which == 0) {
						edit.putString(OsmandSettings.MAP_TILE_OVERLAY_SOURCES, null);
						edit.commit();
						dialog.dismiss();
						updateLayers();
						mapView.refreshMap();
					}
					else {
						if(selected) {
							String currentSettings = OsmandSettings.getMapTileOverlaySourceNameRaw(settings);
							if(currentSettings == null)
								currentSettings = keys.get(which-1);
							else {
								if(!currentSettings.contains(keys.get(which-1)))
									currentSettings += OsmandSettings.MAP_TILE_OVERLAY_SOURCES_SEP + keys.get(which-1);
							}
							edit.putString(OsmandSettings.MAP_TILE_OVERLAY_SOURCES, currentSettings);
							edit.commit();
							String[] split = keys.get(which-1).split(Pattern.quote(DsmMapTileOverlayDownloadActivity.FOLDER_SEPARATOR));
							if(split.length == 7) {
								try {
									float lat1 = (float)Integer.parseInt(split[1])/10000f;
									float lng1 = (float)Integer.parseInt(split[2])/10000f;
									float lat2 = (float)Integer.parseInt(split[3])/10000f;
									float lng2 = (float)Integer.parseInt(split[4])/10000f;
									setDsmMapDownloadViewable(split[0],lat1 + (lat2-lat1)/2,lng1 + (lng2-lng1)/2,lat1,lng1,lat2,lng2);
									LatLon latLon = OsmandSettings.getAndClearMapLocationToShow(settings);
									LatLon cur = new LatLon(mapView.getLatitude(), mapView.getLongitude());
									mapView.refreshMap();
									if (latLon != null && !latLon.equals(cur)) {
										mapView.getAnimatedDraggingThread().startMoving(cur.getLatitude(), cur.getLongitude(), latLon.getLatitude(),
												latLon.getLongitude(), mapView.getZoom(), OsmandSettings.getMapZoomToShow(settings), mapView.getSourceTileSize(),
												mapView.getRotate(), true);
									}
								} catch (Exception e) {
								}
							}
						} else {
							String[] currentList = OsmandSettings.getMapTileOverlaySourceName(settings);
							String currentSettings = "";
							for(String cm : currentList) {
								if(!cm.equals(keys.get(which-1))) {
									if(currentSettings.length() > 0)
										currentSettings += OsmandSettings.MAP_TILE_OVERLAY_SOURCES_SEP;
									currentSettings += cm;
								}
							}
							if(currentSettings.length() == 0) {
								edit.putString(OsmandSettings.MAP_TILE_OVERLAY_SOURCES, null);
							} else {
								edit.putString(OsmandSettings.MAP_TILE_OVERLAY_SOURCES, currentSettings);
							}
							edit.commit();								
						}
					}
					
					try {
						for(ITileSource ts : OsmandSettings.getMapTileOverlaySource(settings)) {
							((OsmandApplication)getApplication()).getResourceManager().orderMapSourceList(ts);
						}
					} catch (Exception e) {}
					updateLayers();
					mapView.refreshMap();
				}
				
			});
		builder.show();
		}
	}
	
	public void contextMenuPoint(final double latitude, final double longitude){
		contextMenuPoint(latitude, longitude, null, null);
	}
	
    public void contextMenuPoint(final double latitude, final double longitude, List<String> additionalItems, 
    		final DialogInterface.OnClickListener additionalActions){
    	Builder builder = new AlertDialog.Builder(this);
    	final int sizeAdditional = additionalActions == null || additionalItems == null ? 0 : additionalItems.size();
    	List<String> actions = new ArrayList<String>();
    	if(sizeAdditional > 0){
    		actions.addAll(additionalItems);
    	}
    	final int[] contextMenuStandardActions = new int[]{
    			R.string.context_menu_item_navigate_point,
    			R.string.context_menu_item_search_poi,
    			R.string.context_menu_item_show_route_to,
    			R.string.context_menu_item_show_route,
    			R.string.context_menu_item_add_favorite,
    			R.string.context_menu_item_share_location,
    			R.string.context_menu_item_add_waypoint,
    			R.string.context_menu_item_update_map,
    			R.string.context_menu_item_download_map
    	};
    	for(int j = 0; j<contextMenuStandardActions.length; j++){
    		actions.add(getResources().getString(contextMenuStandardActions[j]));
    	}
    	
    	builder.setItems(actions.toArray(new String[actions.size()]), new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface dialog, int which) {
				if(which < sizeAdditional){
					additionalActions.onClick(dialog, which);
					return;
				}
				int standardId = contextMenuStandardActions[which - sizeAdditional];
				if(standardId == R.string.context_menu_item_navigate_point){
					navigateToPoint(new LatLon(latitude, longitude));
				} else if(standardId == R.string.context_menu_item_search_poi){
					Intent intent = new Intent(MapActivity.this, SearchPoiFilterActivity.class);
					intent.putExtra(SearchPoiFilterActivity.SEARCH_LAT, latitude);
					intent.putExtra(SearchPoiFilterActivity.SEARCH_LON, longitude);
					intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
					startActivity(intent);
				} else if(standardId == R.string.context_menu_item_show_route_to){
					navigateToPoint(new LatLon(latitude, longitude));
					getDirectionsFromCurrentLocation();
					contextMenuLayer.clearPoint();
				} else if(standardId == R.string.context_menu_item_show_route){
					getDirections(latitude, longitude, false);
				} else if(standardId == R.string.context_menu_item_add_favorite){
					mapActions.addFavouritePoint(latitude, longitude);
				} else if(standardId == R.string.context_menu_item_share_location){
					mapActions.shareLocation(latitude, longitude, mapView.getZoom());
				} else if(standardId == R.string.context_menu_item_add_waypoint){
					mapActions.addWaypoint(latitude, longitude, savingTrackHelper);
				} else if(standardId == R.string.context_menu_item_update_map){
					mapActions.reloadTile(mapView.getZoom(), latitude, longitude);
				} else if(standardId == R.string.context_menu_item_download_map){
					DownloadTilesDialog dlg = new DownloadTilesDialog(MapActivity.this, 
							(OsmandApplication) getApplication(), mapView);
					dlg.openDialog();
				}
			}
    	});
		builder.create().show();
    }
    
	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
	}
	
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
	  super.onConfigurationChanged(newConfig);
	  FrameLayout main = (FrameLayout) this.findViewById(R.id.MainFrame);
	  main.removeView(dsmSpeedometerLayer);
	  this.dsmSpeedometerLayer = new DsmSpeedometerLayer(this);
	  dsmSpeedometerLayer.setVisibility(View.GONE);
	  main.addView(dsmSpeedometerLayer);
	  
	  ApplicationMode mode = OsmandSettings.getApplicationMode(settings);
	  if(mode == ApplicationMode.GAUGE)
		  switchApplicationMode(mode);
//	  mapView.clearPerspective();
//	  setContentView(R.layout.main);
	}

	private void showAllSelectedMaps() {
		this.runOnUiThread(new Runnable() {
			@Override
			public void run() {
				for(DsmMapDownload map : DsmResourceManager.getDsmResourceManager((OsmandApplication)getApplication()).getActiveDsmMaps()) {
					if(map != null)
						DsmResourceManager.getDsmResourceManager((OsmandApplication)getApplication()).showDsmMap(map);
				}
			}
		});
	}

	private static Toast singleModeToast = null;
	
	private enum ROTATEMODE {
		COMPASS("Adjust Bearing"), ZOOM("Adjust Zoom"), MUSIC("Adjust Media"), OVERLAYALPHA("Adjust Overlay Transparency");
		private String toastMessage;
		private ROTATEMODE(String toastMessage) {
			this.toastMessage = toastMessage;
		} 
		private ROTATEMODE next() {
		     return this.ordinal() < ROTATEMODE.values().length - 1
		         ? ROTATEMODE.values()[this.ordinal() + 1]
		         : ROTATEMODE.values()[0];
		}
		public ROTATEMODE getValidNext(MapActivity mapActivity, AudioManager audioManager,SharedPreferences settings) {
			ROTATEMODE validNext = next();
			if(validNext == MUSIC && !audioManager.isMusicActive())
				return validNext.getValidNext(mapActivity,audioManager,settings);
			if(validNext == OVERLAYALPHA && OsmandSettings.getMapTileOverlaySourceName(settings).length == 0)
				return validNext.getValidNext(mapActivity,audioManager,settings);
			if(singleModeToast != null) {
				singleModeToast.cancel();
			}
			singleModeToast = Toast.makeText(mapActivity, validNext.toastMessage, Toast.LENGTH_SHORT);
			singleModeToast.show();
			return validNext;
		}
	}

	private ROTATEMODE rotateMode = ROTATEMODE.COMPASS;
	private int lastX = 0;
	@Override
	public void joystickMoved(int x, int y) {
		try {
			x = -convertJoystickNumbers(x);
			y = -convertJoystickNumbers(y);	
			if (rotateMode == ROTATEMODE.MUSIC) {
				if(x == 2) {
					if(lastX != x)
						mediaNext();
				} else if(x == -2) {
					if(lastX != x)
						mediaPrevious();
				}
			} else {
				int multiplier = 7;
				int centerX = mapView.getCenterPointX();
				int centerY = mapView.getCenterPointY();
				if(mapView.showPerspective()) {
					multiplier = 5;
					float[] pc = mapView.getPerspectiveCenter();
					centerX = (int)pc[0];
					centerY = (int)pc[1];
				}
				LatLon l = mapView.getLatLonFromScreenPoint(centerX + x * multiplier, centerY + y * multiplier);
				setMapLocation(l.getLatitude(), l.getLongitude());
			}
			lastX = x;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private int convertJoystickNumbers(int num) {
		int move = 0;
		switch(num) {
			case 1:
				move = -2;
				break;
			case 2:
				move = -1;
				break;
			case 3:
				move = 1;
				break;
			case 4:
				move = 2;
				break;
		}
		return move;
	}
	
	
	@Override
	public void buttonClicked(int buttonType) {
		switch(buttonType) {
		case DsmRemoteControlManager.D2D:
			if(!isMapLinkedToLocation()){
				backToLocationImpl();
			} else {
				setCurrentLocationAsFavorite();
			}
			break;
		case DsmRemoteControlManager.D3D:
			if (rotateMode == ROTATEMODE.MUSIC) {
				mediaPlayPause();
			} else {
				switchApplicationMode(null);
			}
			break;
		case DsmRemoteControlManager.D4D:
			rotateMode = rotateMode.getValidNext(this,audioManager,settings);
			break;
		case 5:

			break;
		case 7:
			remoteRotate(false);
			break;
		case 8:
			remoteRotate(true);
			break;
		}
	}
	private long lastRotate = System.currentTimeMillis();
	private boolean lastZoom = false;
	private void remoteRotate(boolean forward) {
		if(System.currentTimeMillis()-lastRotate > 50) {
			if(rotateMode == ROTATEMODE.COMPASS) {
				int degree;
				if(!forward)
					degree = -9;
				else
					degree = 9;
				mapView.rotateTo(mapView.getRotate() + degree);
			} else if (rotateMode == ROTATEMODE.ZOOM) {
				if(!forward && !lastZoom)
					zoomIn();
				else if(forward && lastZoom)
					zoomOut();
				lastZoom = forward;
			} else if (rotateMode == ROTATEMODE.MUSIC) {
				if(!forward)
					audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 1);
				else
					audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, 1);
			} else if (rotateMode == ROTATEMODE.OVERLAYALPHA) {
				if(!forward)
					overlayAlpha.setProgress(OsmandSettings.getMapTileOverlayAlpha(settings)+20);
				else
					overlayAlpha.setProgress(OsmandSettings.getMapTileOverlayAlpha(settings)-20);
			}
			lastRotate = System.currentTimeMillis();
		}
	}
	private void mediaNext() {
		Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON);
		synchronized (this) {
		            i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
		            sendOrderedBroadcast(i, null);

		            i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT));
		            sendOrderedBroadcast(i, null);
		 }
	}
	private void mediaPrevious() {
		Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON);
		synchronized (this) {
		            i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
		            sendOrderedBroadcast(i, null);

		            i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
		            sendOrderedBroadcast(i, null);
		 }
	}
	private void mediaPlayPause() {
		Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON);
		synchronized (this) {
					int action = KeyEvent.KEYCODE_MEDIA_PAUSE;
					if(!audioManager.isMusicActive()) {
						action = KeyEvent.KEYCODE_MEDIA_PLAY;
					}
		            i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, action));
		            sendOrderedBroadcast(i, null);

		            i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, action));
		            sendOrderedBroadcast(i, null);
		 }
	}
	public void setCurrentLocationAsFavorite() {
		if(locationLayer.getLastKnownLocation() != null) {
			final FavouritesDbHelper helper = ((OsmandApplication)this.getApplication()).getFavorites();
			NumberFormat nf = DecimalFormat.getInstance();
			nf.setMaximumFractionDigits(4);
			String lat = nf.format(locationLayer.getLastKnownLocation().getLatitude());
			String lng = nf.format(locationLayer.getLastKnownLocation().getLongitude());
			final FavouritePoint p = new FavouritePoint(locationLayer.getLastKnownLocation().getLatitude(), locationLayer.getLastKnownLocation().getLongitude(), lat + "," + lng);
			boolean added = helper.addFavourite(p);
			if (added) {
				Toast.makeText(this, MessageFormat.format(getString(R.string.add_favorite_dialog_favourite_added_template), "current location"), Toast.LENGTH_SHORT).show();
			}
			this.getMapView().refreshMap();
		}
	}
}
